﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Patrols;

public class GameModel : SSActionManager, ISSActionCallback {
    public GameObject PatrolItem, HeroItem, sceneModelItem, canvasItem;
    private SceneController scene;
    private GameObject myHero, sceneModel, canvasAndText;
    private List<GameObject> PatrolSet;
    private List<int> PatrolLastDir;
    private Holes myHoles;

    // 巡逻兵正常状态的速度
    private const float PERSON_SPEED_NORMAL = 0.01f;
    // 巡逻兵追捕状态的速度
    private const float PERSON_SPEED_CATCHING = 0.01f;

    void Awake() {
        PatrolFactory.getInstance().initItem(PatrolItem);
        myHoles = new Holes();
        myHoles.leftUpHole = new Hole(-4.0f, -1.0f, 16.0f, 17.0f);
        myHoles.leftMidHole = new Hole(-6.0f, -5.0f, 10.0f, 14.0f);
        myHoles.leftDownHole = new Hole(-4.0f, -1.0f, 6.5f, 7.5f);
        myHoles.MidHole = new Hole(0.0f, 1.5f, 10.0f, 14.0f);
        myHoles.rightUpHole = new Hole(2.0f, 4.0f, 17.0f, 18.0f);
        myHoles.rightMidHole = new Hole(4.5f, 5.5f, 10.0f, 14.0f);
        myHoles.rightDownHole = new Hole(2.0f, 4.0f, 8.0f, 9.0f);
    }

    protected new void Start () {
        scene = SceneController.getInstance();
        scene.setGameModel(this);

        // 生产英雄+巡逻兵
        genHero();
        genPatrols();
        sceneModel = Instantiate(sceneModelItem);
        canvasAndText = Instantiate(canvasItem);
    }

    protected new void Update() {
        base.Update();
    }

    
    void genHero() {
        myHero = Instantiate(HeroItem);
    }

    void genPatrols() {
        PatrolSet = new List<GameObject>(6);
        PatrolLastDir = new List<int>(6);
        Vector3[] posSet = PatrolFactory.getInstance().getPosSet();
        for (int i = 0; i < 6; i++) {
            GameObject newPatrol = PatrolFactory.getInstance().getPatrol();
            newPatrol.transform.position = posSet[i];
            newPatrol.name = "Patrol" + i;
            PatrolLastDir.Add(-2);
            PatrolSet.Add(newPatrol);
            addRandomMovement(newPatrol, true);
        }
    }

    // hero移动
    public void heroMove(int dir) {
        myHero.transform.rotation = Quaternion.Euler(new Vector3(0, dir * 90, 0));
        int index = getHeroStandOnArea();

        Vector3 herolPos = myHero.transform.position;
        float posX = herolPos.x;
        float posZ = herolPos.z;
        switch (dir) {
            case Diretion.UP:
                heroMoveUp(index, posX, posZ);
                // myHero.transform.position += new Vector3(0, 0, 0.1f);
                break;
            case Diretion.DOWN:
                heroMoveDown(index, posX, posZ);
                // myHero.transform.position += new Vector3(0, 0, -0.1f);
                break;
            case Diretion.LEFT:
                heroMoveLeft(index, posX, posZ);
                // myHero.transform.position += new Vector3(-0.1f, 0, 0);
                break;
            case Diretion.RIGHT:
                heroMoveRight(index, posX, posZ);
                // myHero.transform.position += new Vector3(0.1f, 0, 0);
                break;
        }
    }

    private void heroMoveUp(int index, float posX, float posZ) {
        switch (index) {
            case 0:
            case 1:
            case 2:
                if (posZ + 1 < FenchLocation.FenchTop)
                    myHero.transform.position += new Vector3(0, 0, 0.1f);
                break;
            case 3:
                if (posZ + 1 < FenchLocation.FenchHori) {
                    myHero.transform.position += new Vector3(0, 0, 0.1f);
                } else if(myHoles.leftMidHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(0, 0, 1.0f);
                }
                break;
            case 4:
                if (posZ + 1 < FenchLocation.FenchHori) {
                    myHero.transform.position += new Vector3(0, 0, 0.1f);
                } else if(myHoles.MidHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(0, 0, 1.0f);
                }
                break;
            case 5:
                if (posZ + 1 < FenchLocation.FenchHori) {
                    myHero.transform.position += new Vector3(0, 0, 0.1f);
                } else if(myHoles.rightMidHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(0, 0, 1.0f);
                }
                break;
        }
    }

    private void heroMoveDown(int index, float posX, float posZ) {
        switch (index) {
            case 0:
                if (posZ - 1 > FenchLocation.FenchHori) {
                    myHero.transform.position += new Vector3(0, 0, -0.1f);
                } else if(myHoles.leftMidHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(0, 0, -1.0f);
                }
                break;
            case 1:
                if (posZ - 1 > FenchLocation.FenchHori) {
                    myHero.transform.position += new Vector3(0, 0, -0.1f);
                } else if(myHoles.MidHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(0, 0, -1.0f);
                }
                break;
            case 2:
                if (posZ - 1 > FenchLocation.FenchHori) {
                    myHero.transform.position += new Vector3(0, 0, -0.1f);
                } else if(myHoles.rightMidHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(0, 0, -1.0f);
                }
                break;
            case 3:
            case 4:
            case 5:
                if (posZ - 1 > FenchLocation.FenchBottom)
                    myHero.transform.position += new Vector3(0, 0, -0.1f);
                break;
        }
    }

    private void heroMoveLeft(int index, float posX, float posZ) {
        switch (index) {
            case 0:
            case 3:
                if (posX - 1 > FenchLocation.FenchLeft)
                    myHero.transform.position += new Vector3(-0.1f, 0, 0);
                break;
            case 1:
                if (posX - 1 > FenchLocation.FenchVertLeft) {
                    myHero.transform.position += new Vector3(-0.1f, 0, 0);
                } else if(myHoles.leftUpHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(-1.0f, 0, 0);
                }
                break;
            case 4:
                if (posX - 1 > FenchLocation.FenchVertLeft) {
                    myHero.transform.position += new Vector3(-0.1f, 0, 0);
                } else if(myHoles.leftDownHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(-1.0f, 0, 0);
                }
                break;
            case 2:
                if (posX - 1 > FenchLocation.FenchVertRight) {
                    myHero.transform.position += new Vector3(-0.1f, 0, 0);
                } else if(myHoles.rightUpHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(-1.0f, 0, 0);
                }
                break;
            case 5:
                if (posX - 1 > FenchLocation.FenchVertRight) {
                    myHero.transform.position += new Vector3(-0.1f, 0, 0);
                } else if(myHoles.rightDownHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(-1.0f, 0, 0);
                }
                break;
        }
    }

    private void heroMoveRight(int index, float posX, float posZ) {
        switch (index) {
            case 0:
                if (posX + 1 < FenchLocation.FenchVertLeft) {
                    myHero.transform.position += new Vector3(0.1f, 0, 0);
                } else if(myHoles.leftUpHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(1.0f, 0, 0);
                }
                break;
            case 3:
                if (posX + 1 < FenchLocation.FenchVertLeft) {
                    myHero.transform.position += new Vector3(0.1f, 0, 0);
                } else if(myHoles.leftDownHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(1.0f, 0, 0);
                }
                break;
            case 1:
                if (posX + 1 < FenchLocation.FenchVertRight) {
                    myHero.transform.position += new Vector3(0.1f, 0, 0);
                } else if(myHoles.rightUpHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(1.0f, 0, 0);
                }
                break;
            case 4:
                if (posX + 1 < FenchLocation.FenchVertRight) {
                    myHero.transform.position += new Vector3(0.1f, 0, 0);
                } else if(myHoles.rightDownHole.isInHole(posX, posZ)) {
                    myHero.transform.position += new Vector3(1.0f, 0, 0);
                }
                break;
            case 2:
            case 5:
                if (posX + 1 < FenchLocation.FenchRight)
                    myHero.transform.position += new Vector3(0.1f, 0, 0);
                break;
        }
    }

    // 动作结束后
    public void SSActionEvent(SSAction source, SSActionEventType eventType = SSActionEventType.Completed, 
        SSActionTargetType intParam = SSActionTargetType.Normal, string strParam = null, object objParam = null) {
        if (intParam == SSActionTargetType.Normal) {
            addRandomMovement(source.gameObject, true);
        } else {
            addDirectMovement(source.gameObject);
        }
    }

    // isActive说明是否主动变向（动作结束）
    public void addRandomMovement(GameObject sourceObj, bool isActive) {
        int index = getIndexOfObj(sourceObj);
        int randomDir = getRandomDirection(index, isActive);
        PatrolLastDir[index] = randomDir;

        sourceObj.transform.rotation = Quaternion.Euler(new Vector3(0, randomDir * 90, 0));
        Vector3 target = sourceObj.transform.position;
        switch (randomDir) {
            case Diretion.UP:
                target += new Vector3(0, 0, 1);
                break;
            case Diretion.DOWN:
                target += new Vector3(0, 0, -1);
                break;
            case Diretion.LEFT:
                target += new Vector3(-1, 0, 0);
                break;
            case Diretion.RIGHT:
                target += new Vector3(1, 0, 0);
                break;
        }
        addSingleMoving(sourceObj, target, PERSON_SPEED_NORMAL, false);
    }
    int getIndexOfObj(GameObject sourceObj) {
        string name = sourceObj.name;
        char cindex = name[name.Length - 1];
        int result = cindex - '0';
        return result;
    }
    int getRandomDirection(int index, bool isActive) {
        // -1左  0上  1右  2下
        int randomDir = Random.Range(-1, 3);

        // 当碰撞时，不走同方向
        if (!isActive) {    
            while (PatrolLastDir[index] == randomDir || PatrolOutOfArea(index, randomDir)) {
                randomDir = Random.Range(-1, 3);
            }
        } else {
            while (PatrolLastDir[index] == 0 && randomDir == 2 
                || PatrolLastDir[index] == 2 && randomDir == 0
                || PatrolLastDir[index] == 1 && randomDir == -1
                || PatrolLastDir[index] == -1 && randomDir == 1
                || PatrolOutOfArea(index, randomDir)) {
                randomDir = Random.Range(-1, 3);
            }
        }
        return randomDir;
    }
    // 判断巡逻兵是否越界
    bool PatrolOutOfArea(int index, int randomDir) {
        Vector3 patrolPos = PatrolSet[index].transform.position;
        float posX = patrolPos.x;
        float posZ = patrolPos.z;
        switch (index) {
            case 0:
                if (randomDir == 1 && posX + 1 > FenchLocation.FenchVertLeft || randomDir == 2 && posZ - 1 < FenchLocation.FenchHori)
                    return true;
                break;
            case 1:
                if (randomDir == 1 && posX + 1 > FenchLocation.FenchVertRight || randomDir == -1 && posX - 1 < FenchLocation.FenchVertLeft || randomDir == 2 && posZ - 1 < FenchLocation.FenchHori)
                    return true;
                break;
            case 2:
                if (randomDir == -1 && posX - 1 < FenchLocation.FenchVertRight || randomDir == 2 && posZ - 1 < FenchLocation.FenchHori)
                    return true;
                break;
            case 3:
                if (randomDir == 1 && posX + 1 > FenchLocation.FenchVertLeft || randomDir == 0 && posZ + 1 > FenchLocation.FenchHori)
                    return true;
                break;
            case 4:
                if (randomDir == 1 && posX + 1 > FenchLocation.FenchVertRight || randomDir == -1 && posX - 1 < FenchLocation.FenchVertLeft || randomDir == 0 && posZ + 1 > FenchLocation.FenchHori)
                    return true;
                break;
            case 5:
                if (randomDir == -1 && posX - 1 < FenchLocation.FenchVertRight || randomDir == 0 && posZ + 1 > FenchLocation.FenchHori)
                    return true;
                break;
        }
        return false;
    }

    // 巡逻兵追捕hero
    public void addDirectMovement(GameObject sourceObj) {
        int index = getIndexOfObj(sourceObj);
        PatrolLastDir[index] = -2;

        sourceObj.transform.LookAt(sourceObj.transform);
        Vector3 oriTarget = myHero.transform.position - sourceObj.transform.position;
        Vector3 target = new Vector3(oriTarget.x / 4.0f, 0, oriTarget.z / 4.0f);
        target += sourceObj.transform.position;
        addSingleMoving(sourceObj, target, PERSON_SPEED_CATCHING, true);
    }

    void addSingleMoving(GameObject sourceObj, Vector3 target, float speed, bool isCatching) {
        this.runAction(sourceObj, CCMoveToAction.CreateSSAction(target, speed, isCatching), this);
    }

    void addCombinedMoving(GameObject sourceObj, Vector3[] target, float[] speed, bool isCatching) {
        List<SSAction> acList = new List<SSAction>();
        for (int i = 0; i < target.Length; i++) {
            acList.Add(CCMoveToAction.CreateSSAction(target[i], speed[i], isCatching));
        }
        CCSequeneActions MoveSeq = CCSequeneActions.CreateSSAction(acList);
        this.runAction(sourceObj, MoveSeq, this);
    }

    // 获取hero所在区域编号
    public int getHeroStandOnArea() {
        return myHero.GetComponent<HeroStatus>().standOnArea;
    }
}
